import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { DeputyGeneral } from "../entities/deputy-general.entity";
import { DeputyAttributePointsEntity } from "../entities/deputy-attribute-points.entity";

@Injectable()
export class DeputyAttributeService {
  constructor(
    @InjectRepository(DeputyGeneral)
    private deputyRepository: Repository<DeputyGeneral>,
    @InjectRepository(DeputyAttributePointsEntity)
    private deputyAttrPointsRepo: Repository<DeputyAttributePointsEntity>
  ) {}

  private calculateBase(roleType: number) {
    const base: Record<
      number,
      { hp: number; mp: number; ap: number; sp: number }
    > = {
      1: { hp: 360, mp: 200, ap: 80, sp: 10 },
      2: { hp: 330, mp: 280, ap: 70, sp: 10 },
      3: { hp: 300, mp: 360, ap: 60, sp: 10 },
    };
    return base[roleType] || base[1];
  }

  private calculateLevelCoeff(level: number) {
    const d5 = Math.floor(level / 5);
    const m5 = level % 5;
    return 20 + 4 * d5 + Math.max(0, m5 - 1);
  }

  async ensurePoints(deputyId: number) {
    let pts = await this.deputyAttrPointsRepo.findOne({ where: { deputyId } });
    if (!pts) {
      pts = this.deputyAttrPointsRepo.create({
        deputyId,
        strength: 0,
        constitution: 0,
        intelligence: 0,
        agility: 0,
        availablePoints: 0,
      });
      await this.deputyAttrPointsRepo.save(pts);
    }
    return pts;
  }

  async calculate(deputyId: number) {
    const deputy = await this.deputyRepository.findOne({
      where: { id: deputyId },
    });
    if (!deputy) throw new Error("副将不存在");
    const pts = await this.ensurePoints(deputyId);

    const base = this.calculateBase(deputy.roleType);
    const coeff = this.calculateLevelCoeff(deputy.lvl);

    const s = deputy.lvl + pts.strength;
    const c = deputy.lvl + pts.constitution;
    const i = deputy.lvl + pts.intelligence;
    const a = deputy.lvl + pts.agility;

    let hp: number, mp: number, ap: number, sp: number;
    switch (deputy.roleType) {
      case 1:
        hp = Math.floor(1.1 * coeff * c) + base.hp;
        mp = Math.floor(0.6 * coeff * i) + base.mp;
        ap = Math.floor(0.26 * coeff * s) + base.ap;
        sp = Math.floor(1.0 * (a + base.sp));
        break;
      case 2:
        hp = Math.floor(1.1 * coeff * c) + base.hp;
        mp = Math.floor(1.0 * coeff * i) + base.mp;
        ap = Math.floor(0.2 * coeff * s) + base.ap;
        sp = Math.floor(
          (0.8 + (deputy.trans_count || 0) * 0.05) * (a + base.sp)
        );
        break;
      case 3:
        hp = Math.floor(1.0 * coeff * c) + base.hp;
        mp = Math.floor(1.3 * coeff * i) + base.mp;
        ap = Math.floor(0.14 * coeff * s) + base.ap;
        sp = Math.floor(1.1 * (a + base.sp));
        break;
      default:
        hp = base.hp;
        mp = base.mp;
        ap = base.ap;
        sp = base.sp;
    }

    return {
      hp: Math.max(1, hp),
      mp: Math.max(1, mp),
      ap: Math.max(1, ap),
      sp: Math.max(1, sp),
      // 点数显示：等级 + 已分配，与主将一致
      app: s,
      hpp: c,
      mpp: i,
      spp: a,
      p: pts.availablePoints,
    };
  }

  async onLevelUp(deputyId: number, newLevel: number) {
    const pts = await this.ensurePoints(deputyId);
    // 每级4点，且四维各+1（与主将一致：总共+4，其中默认+1*4，未分配+4）
    const shouldTotal = (newLevel - 1) * 4;
    const currentTotal =
      pts.strength +
      pts.constitution +
      pts.intelligence +
      pts.agility +
      pts.availablePoints;
    if (currentTotal < shouldTotal) {
      const delta = shouldTotal - currentTotal;
      pts.availablePoints += delta;
    }
    await this.deputyAttrPointsRepo.save(pts);
  }

  /**
   * 分配副将未分配属性点
   */
  async allocatePoints(
    deputyId: number,
    strengthDelta: number = 0,
    constitutionDelta: number = 0,
    intelligenceDelta: number = 0,
    agilityDelta: number = 0
  ) {
    const pts = await this.ensurePoints(deputyId);

    const s = Math.max(0, Number(strengthDelta) || 0);
    const c = Math.max(0, Number(constitutionDelta) || 0);
    const i = Math.max(0, Number(intelligenceDelta) || 0);
    const a = Math.max(0, Number(agilityDelta) || 0);
    const total = s + c + i + a;

    if (total <= 0) {
      return pts;
    }

    if (pts.availablePoints < total) {
      throw new Error("属性点不足");
    }

    pts.strength += s;
    pts.constitution += c;
    pts.intelligence += i;
    pts.agility += a;
    pts.availablePoints -= total;

    await this.deputyAttrPointsRepo.save(pts);
    return pts;
  }
}
